package poo.util;

import java.util.*;

@SuppressWarnings("unchecked")
public class ArrayVector<T> implements Vector<T> {

	private int size;
	private T array[];

	public ArrayVector(int capacita) {
		if (capacita <= 0)
			throw new IllegalArgumentException();
		array = ((T[]) new Object[capacita]);
		size = 0;
	}

	public ArrayVector() {
		this(20);
	}

	@Override
	public int size() {
		return size;
	}

	@Override
	public int indexOf(T x) {
		for (int i = 0; i < size; i++)
			if (array[i].equals(x))
				return i;
		return -1;
	}

	@Override
	public boolean contains(T x) {
		return indexOf(x) != -1;
	}

	@Override
	public T get(int indice) {
		if (indice < 0 || indice >= size)
			throw new IndexOutOfBoundsException();
		return (T) array[indice];
	}

	@Override
	public T set(int indice, T x) {
		if (indice < 0 || indice >= size)
			throw new IndexOutOfBoundsException();
		Object y = array[indice];
		array[indice] = x;
		return (T) y;
	}

	@Override
	public void add(T x) {
		if (size == array.length)
			espandi();
		array[size] = x;
		size++;
	}

	private void espandi() {
		Object[] nuovo = new Object[array.length * 2];
		System.arraycopy(array, 0, nuovo, 0, size);
		array = (T[]) nuovo;
	}

	@Override
	public void add(int indice, T x) {
		if (indice < 0 || indice > size)
			throw new IndexOutOfBoundsException();
		if (size == array.length)
			espandi();
		for (int i = size - 1; i >= indice; i--)
			array[i + 1] = array[i];
		array[indice] = x;
		size++;
	}

	@Override
	public T remove(int indice) {
		if (indice < 0 || indice >= size)
			throw new IndexOutOfBoundsException();
		Object y = array[indice];
		for (int i = indice + 1; i < size; i++)
			array[i - 1] = array[i];
		size--;
		array[size] = null;
		if (size < array.length / 2)
			contrai();
		return (T) y;
	}

	@Override
	public void remove(T x) {
		int i = indexOf(x);
		if (i != -1)
			remove(i);
	}

	private void contrai() {
		Object[] nuovo = new Object[array.length / 2];
		System.arraycopy(array, 0, nuovo, 0, size);
		array = (T[]) nuovo;
	}

	@Override
	public void clear() {
		for (int i = 0; i < size; i++)
			array[i] = null;
		size = 0;
	}

	@Override
	public boolean isEmpty() {
		return size == 0;
	}

	@SuppressWarnings("rawtypes")
	@Override
	public Vector subVector(int da, int a) {
		if (da < 0 || da >= size || a < 0 || a > size || da >= a)
			throw new RuntimeException();
		Vector<T> dest = new ArrayVector<T>(a - da);
		for (int i = da; i < a; i++)
			dest.add(array[i]);
		return dest;
	}

	public String toString() {
		StringBuilder sb = new StringBuilder(300);
		sb.append('[');
		for (int i = 0; i < size; i++) {
			sb.append(array[i]);
			if (i < size - 1)
				sb.append(", ");
		}
		sb.append("]");
		return sb.toString();
	}

	public boolean equals(Object x) {
		if (!(x instanceof Vector))
			return false;
		if (x == this)
			return true;
		Vector<T> v = (Vector<T>) x;
		if (this.size != v.size())
			return false;
		for (int i = 0; i < size; i++)
			if (!array[i].equals(v.get(i)))
				return false;
		return true;
	}

	public int hashCode() {
		final int PRIMO = 83;
		int h = 0;
		for (int i = 0; i < size; i++)
			h = h * PRIMO + array[i].hashCode();
		return h;
	}

	public static void main(String[] pazzo) {

		Vector<Integer> v = new ArrayVector<Integer>(5);

		for (int i = 0; i < 10; i++)
			v.add(new Integer(i));
		System.out.println(v);

		v.remove(new Integer(5));
		System.out.println(v);

		v.remove(0);
		System.out.println(v);

		v.clear();
		System.out.println(v + " size=" + v.size());

		Vector<String> w = new ArrayVector<String>(50);
		Scanner sc = new Scanner(System.in);
		System.out.println("Inserisci una parola:");

		for (;;) {
			String s = sc.nextLine();
			if (s.length() == 0) {
				break;
			}
			int j = 0;
			boolean flag = false;
			while (j < w.size() && !flag) {
				String s1 = (String) w.get(j);
				if (s1.compareToIgnoreCase(s) >= 0)
					flag = true;
				else
					j++;
			}
			w.add(j, s);
		}// for
		sc.close();
		System.out.println(w);

		Vector<String> v1 = new ArrayVector<String>();
		v1.add("casa");
		v1.add("dado");
		v1.add("ciao");

		Iterator<String> it = v1.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
			it.remove();
		}
	}

	@Override
	public Iterator<T> iterator() {
		return new VectorIterator();
	}

	private class VectorIterator implements Iterator<T> {
		private int corrente = -1;
		private boolean rimuovibile = false;

		@Override
		public boolean hasNext() {
			return corrente < size - 1;
		}

		@Override
		public T next() {
			if (!hasNext())
				throw new NoSuchElementException();
			corrente++;
			rimuovibile = true;
			return array[corrente];
		}

		@Override
		public void remove() {
			if (!rimuovibile)
				throw new IllegalStateException();
			rimuovibile = false;
			for (int i = corrente + 1; i < size; i++)
				array[i - 1] = array[i];
			size--;
			corrente--;
		}
	}
}
